package com.eastfair.projectcore.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.auth.entity.UserAccount;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.projectcore.dao.MenuMapper;
import com.eastfair.projectcore.dto.MenuDTO;
import com.eastfair.projectcore.dto.MenuSaveDTO;
import com.eastfair.projectcore.dto.MenuUpdateDTO;
import com.eastfair.projectcore.entity.AppMenu;
import com.eastfair.projectcore.entity.Menu;
import com.eastfair.projectcore.entity.ProjectDb;
import com.eastfair.projectcore.enumeration.MenuMenuTypeEnum;
import com.eastfair.projectcore.enumeration.MenuTerminalTypeEnum;
import com.eastfair.projectcore.service.MenuService;
import com.eastfair.projectcore.vo.AppMenuVO;
import com.eastfair.projectcore.vo.MenuVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.boot.service.SuperServiceImpl;

import com.eastfair.uid.model.SelfUidDto;
import com.eastfair.util.CodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 菜单
 * </p>
 *
 * @author ligang
 * @date 2021-07-22
 */
@Slf4j
@Service
@Transactional
public class MenuServiceImpl extends SuperServiceImpl<MenuMapper, Menu> implements MenuService {
//    @Autowired
//    SelfUidService selfUidService;

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(Menu model) {
        //雪花ID,不需要分库分表
//        SelfUidDto selfUidDto = new SelfUidDto();
//        model.setId(selfUidService.getUid(selfUidDto));
        model.setId(DefaultUidGenerator.getUid(0L));
        if (model.getParentId() == null) {
            //组织顶级为0
            model.setParentId(BusinessConstant.parentId);
        }
        //code 码
        if (StringUtils.isBlank(model.getCode())) {
            model.setCode(queryCode(model));
        }
        if (model.getSequence() == null) {
            //排序
            model.setSequence(1);
            if (model.getParentId() != null) {
                model.setSequence(querySort(model.getParentId()));
            }
        }
        return R.successDef();
    }

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<Menu> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    @Override
    public R del(Long id) {
        Menu menu = getById(id);
        if (menu != null) {
            //同时删除旗下子节点
            delChild(menu);
            menu.setIsDeleted(BusinessConstant.DELETE_YES);
            updateById(menu);
        }
        return R.successDef();
    }

    @Override
    public R delChild(Menu menu) {
        if (menu != null) {
            String code = menu.getCode();
            List<Menu> menuList = queryAllOfCode(Arrays.asList(code + ","), null, null);
            if (menuList != null && !menuList.isEmpty()) {
                for (Menu menu1 : menuList) {
                    menu1.setIsDeleted(BusinessConstant.DELETE_YES);
                    updateById(menu1);
                }
            }
        }
        return R.successDef();
    }


    @Override
    public int querySort(Long parentId) {
        if (parentId == 0) {
            return 1;
        }
        List<Menu> menuList = queryEntityOfParentId(parentId);
        if (menuList != null && !menuList.isEmpty()) {
            int max = menuList.stream().mapToInt(s -> s.getSequence()).max().getAsInt();
            return max + 1;
        }
        return 1;
    }

    @Override
    public String queryCode(Menu model) {
        String code = nonredundantCode();
        if (model.getParentId() != 0) {
            Menu menu = getById(model.getParentId());
            if (menu != null) {
                code = menu.getCode() + "," + code;
            }
        }
        return code;
    }

    /**
     * 获取不重复的code
     *
     * @return
     */
    public String nonredundantCode() {
        String code = CodeUtils.randomCode(6);
        //是否重复
        int num = queryCodeSize(code);
        if (num > 0) {
            nonredundantCode();
        }
        return code;
    }

    @Override
    public void sortTop(Long id) {
        Menu menu = getById(id);
        if (menu.getParentId() == 0) {
            return;
        }
        menu.setSequence(1);
        updateById(menu);
        List<Menu> menuList = queryEntityOfParentId(menu.getParentId());
        int num = 2;
        if (menuList != null && !menuList.isEmpty()) {
            for (Menu menu1 : menuList) {
                if (menu1.getId().equals(id)) {
                    menu1.setSequence(num++);
                    updateById(menu1);
                }
            }
        }
    }

    @Override
    public void initSort(Long parentId) {
        List<Menu> menuList = queryEntityOfParentId(parentId);
        if (menuList != null && !menuList.isEmpty()) {
            int num = 1;
            for (Menu menu1 : menuList) {
                menu1.setSequence(num++);
                updateById(menu1);
            }
        }
    }

    @Override
    public List<Menu> queryAllOfCode(List<String> rightCodes, List<String> leftCodes, MenuDTO menuDTO) {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        if (rightCodes != null && !rightCodes.isEmpty()) {
//            queryWrapper.lambda().likeRight(Menu::getCode, rightCode);
            queryWrapper.and(wrapper -> {
                for (int i = 0; i < rightCodes.size(); i++) {
                    wrapper.likeRight("code", rightCodes.get(i));
                    if (i < (rightCodes.size() - 1)) {
                        wrapper.or();
                    }
                }
            });
        }
        if (leftCodes != null && !leftCodes.isEmpty()) {
//            queryWrapper.lambda().likeLeft(Menu::getCode, leftCode);
            queryWrapper.and(wrapper -> {
                for (int i = 0; i < leftCodes.size(); i++) {
                    wrapper.likeLeft("code", leftCodes.get(i));
                    if (i < (leftCodes.size() - 1)) {
                        wrapper.or();
                    }
                }
            });
        }
        queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
        //是否显示
//        queryWrapper.lambda().eq(Menu::getIsShow, BusinessConstant.YES);
        //是否生效
//        queryWrapper.lambda().eq(Menu::getIsEnabled, BusinessConstant.YES);

        if (menuDTO != null) {
            if (menuDTO.getMenuMenuTypeEnumList() != null && !menuDTO.getMenuMenuTypeEnumList().isEmpty()) {
                queryWrapper.lambda().in(Menu::getMenuType, menuDTO.getMenuMenuTypeEnumList());
            }
            if (menuDTO.getIsShow() != null) {
                //是否显示
                queryWrapper.lambda().eq(Menu::getIsShow, menuDTO.getIsShow());
            }
            if (menuDTO.getIsEnabled() != null) {
                //是否生效
                queryWrapper.lambda().eq(Menu::getIsEnabled, menuDTO.getIsEnabled());
            }
        }
        //排序查询
        queryWrapper.orderByAsc("sequence");
        List<Menu> menuList = list(queryWrapper);
        return menuList;
    }

    @Override
    public int queryCodeSize(String code) {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(code)) {
            queryWrapper.lambda().eq(Menu::getCode, code);
        }
        queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
        //排序查询
        queryWrapper.orderByAsc("sequence");
        return count(queryWrapper);
    }

    @Override
    public MenuVO loadTree(String parentCode, List<MenuVO> menuVOList) {
        List<MenuVO> tree = new ArrayList<>();
        for (MenuVO menuVo : menuVOList) {
            //找到根节点
            if (menuVo.getCode().equals(parentCode)) {
                tree.add(findChildren(menuVo, menuVOList));
                break;
            }
        }
        return tree.get(0);
    }

    /**
     * 查找menuVo的子节点
     *
     * @param menuVo 根节点
     * @param list
     * @return
     */
    private MenuVO findChildren(MenuVO menuVo, List<MenuVO> list) {
        List<MenuVO> children = new ArrayList<>();
        for (MenuVO node : list) {
            if (node.getParentId().equals(menuVo.getId())) {
                //递归调用
                children.add(findChildren(node, list));
            }
        }
        menuVo.setChildVoList(children.isEmpty() ? null : children);
        menuVo.setIsLeaf(children.isEmpty() ? true : false);
        return menuVo;
    }


    @Override
    public R<Menu> createMenu(MenuSaveDTO menuSaveDTO) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuSaveDTO, menu);
        //校验数据合法性
        R r = verifyMenu(menu);
        if (R.SUCCESS_CODE != r.getCode()) {
            return r;
        }
        //新增
        save(menu);
        return R.success(menu);
    }

    @Override
    public R<Menu> updateMenu(MenuUpdateDTO menuUpdateDTO) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuUpdateDTO, menu);
        //校验数据合法性
        R r = verifyMenu(menu);
        if (R.SUCCESS_CODE != r.getCode()) {
            return r;
        }
        //修改
        updateById(menu);
        return R.success(menu);
    }

    /**
     * 校验参数是否正确
     *
     * @param menu
     * @return
     */
    public R verifyMenu(Menu menu) {
        //校验判断：1必须有上级菜单  2 必须有菜单类型 3必须有菜单名称
        if (menu.getParentId() == null || menu.getMenuType() == null || StringUtils.isBlank(menu.getName())) {
            return R.fail(ExceptionCode.MENU_PARAM_ERROR);
        }
        //如果是外链，必须有外链地址
        if (BusinessConstant.YES == menu.getIsOutLink() && StringUtils.isBlank(menu.getLink())) {
            return R.fail(ExceptionCode.MENU_PARAM_ERROR);
        }
        if (MenuMenuTypeEnum.CATALOG.getCode().equals(menu.getMenuType().getCode())) {
            //目录
        } else if (MenuMenuTypeEnum.MENU.getCode().equals(menu.getMenuType().getCode())) {
            //菜单
        } else if (MenuMenuTypeEnum.BUTTON.getCode().equals(menu.getMenuType().getCode())) {
            //按钮 必须有权限字符
            if (StringUtils.isBlank(menu.getPermission())) {
                return R.fail(ExceptionCode.MENU_PARAM_ERROR);
            }

        }
        return R.success();
    }

    @Override
    public List<Menu> queryEntityOfParentId(Long parentId) {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Menu::getParentId, parentId);
        queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
        //排序查询
        queryWrapper.orderByAsc("sequence");
        return list(queryWrapper);
    }

    @Override
    public MenuVO findAllById(Long id) {
        if (id == null) {
            //查顶级菜单
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
            queryWrapper.lambda().eq(Menu::getParentId, BusinessConstant.parentId);
            //查询用户
            List<Menu> menuList = list(queryWrapper);
            if (menuList != null && !menuList.isEmpty()) {
                id = menuList.get(0).getId();
            }
        }
        Menu menu = getById(id);
        if (menu != null) {
            String code = menu.getCode();
            //只查询菜单和目录
            MenuDTO menuDTO = new MenuDTO();
//            menuDTO.setMenuMenuTypeEnumList(Arrays.asList(MenuMenuTypeEnum.MENU, MenuMenuTypeEnum.CATALOG));
            menuDTO.setIsShow(BusinessConstant.YES);
            menuDTO.setIsEnabled(BusinessConstant.YES);
            List<Menu> childMenuList = queryAllOfCode(Arrays.asList(code), null, null);
            if (childMenuList != null && !childMenuList.isEmpty()) {
                return loadTree(code, doToVos(childMenuList));
            }
        }
        return null;
    }

    @Override
    public MenuVO findAllByIdNoButton(Long id) {
        if (id == null) {
            //查顶级菜单
            QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
            queryWrapper.lambda().eq(Menu::getParentId, BusinessConstant.parentId);
            //查询用户
            List<Menu> menuList = list(queryWrapper);
            if (menuList != null && !menuList.isEmpty()) {
                id = menuList.get(0).getId();
            }
        }

        Menu menu = getById(id);
        if (menu != null) {
            String code = menu.getCode();
            //只查询菜单和目录
            MenuDTO menuDTO = new MenuDTO();
//            menuDTO.setMenuMenuTypeEnumList(Arrays.asList(MenuMenuTypeEnum.MENU, MenuMenuTypeEnum.CATALOG));
            menuDTO.setIsShow(BusinessConstant.YES);
            menuDTO.setIsEnabled(BusinessConstant.YES);
            List<Menu> childMenuList = queryAllOfCode(Arrays.asList(code), null, null);
            //查询按钮级别菜单
            List<Menu> buttonMenuList = childMenuList.stream().filter(s -> MenuMenuTypeEnum.BUTTON.getCode().equals(s.getMenuType().getCode())).collect(Collectors.toList());
            //过滤掉按钮级别菜单
            childMenuList = childMenuList.stream().filter(s -> !MenuMenuTypeEnum.BUTTON.getCode().equals(s.getMenuType().getCode())).collect(Collectors.toList());
            if (childMenuList != null && !childMenuList.isEmpty()) {
                MenuVO menuVO = loadTree(code, doToVos(childMenuList));
//                if(buttonMenuList !=null && !buttonMenuList.isEmpty()){
//                    menuVO.setButtonPermissionList(buttonMenuList.stream().map(Menu::getPermission).collect(Collectors.toList()));
//                }
                return menuVO;
            }
        }
        return null;
    }

    @Override
    public void clearParentNodeData(Long parentId) {
        if (parentId == null) {
            return;
        }
//        Menu menu = getById(parentId);
//        if (menu != null) {
//            menu.setIsDirectory(BusinessConstant.YES);
//            menu.setLinkType("");
//            menu.setLink("");
//            menu.setParam("");
//            updateById(menu);
//        }
    }

    @Override
    public List<MenuVO> findAllByChildId(List<Long> childIds) {
        List<MenuVO> result = new ArrayList<>();
        if (childIds != null && !childIds.isEmpty()) {
            List<Menu> menuList = listByIds(childIds);
            if (menuList != null && !menuList.isEmpty()) {
                //过滤父级菜单信息
                Set<String> parentMenuSet = new HashSet<>();
                List<String> childCodes = menuList.stream().map(Menu::getCode).collect(Collectors.toList());
                for (Menu menu : menuList) {
                    parentMenuSet.add(menu.getCode().substring(0, menu.getCode().indexOf(",")));
                }
                MenuDTO menuDTO = new MenuDTO();
//            menuDTO.setMenuMenuTypeEnumList(Arrays.asList(MenuMenuTypeEnum.MENU, MenuMenuTypeEnum.CATALOG));
                menuDTO.setIsShow(BusinessConstant.YES);
                menuDTO.setIsEnabled(BusinessConstant.YES);
                List<Menu> childMenuList = queryAllOfCode(new ArrayList<>(parentMenuSet), null, menuDTO);
                if (childMenuList != null && !childMenuList.isEmpty()) {
                    //过滤非节点菜单信息
                    childMenuList = childMenuList.stream().filter(p -> {
                        for (String str : childCodes) {
                            if (str.indexOf(p.getCode()) > -1) {
                                return true;
                            }
                        }
                        return false;
                    }).collect(Collectors.toList());
                    //组装菜单信息
                    for (String code : parentMenuSet) {
                        MenuVO menuVo = loadTree(code, doToVos(childMenuList));
                        if (menuVo != null) {
                            result.add(menuVo);
                        }
                    }
                }
            }
        }
        return result;
    }

    @Override
    public List<String> findButtonPermission() {
        //查询用户是否存在
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Menu::getIsDeleted, BusinessConstant.DELETE_NO);
        queryWrapper.lambda().eq(Menu::getMenuType, MenuMenuTypeEnum.BUTTON);
        //查询用户
        List<Menu> menuList = list(queryWrapper);
        if (menuList != null && !menuList.isEmpty()) {
            List<String> permissionList = menuList.stream().map(Menu::getPermission).collect(Collectors.toList());
            return permissionList;
        }
        return null;
    }

    @Override
    public List<String> findPermissionAllByChildId(List<Long> childIds) {
        List<MenuVO> result = new ArrayList<>();
        if (childIds != null && !childIds.isEmpty()) {
            List<Menu> menuList = listByIds(childIds);
            if (menuList != null && !menuList.isEmpty()) {
                return menuList.stream().filter(s -> StringUtils.isNotBlank(s.getPermission())).map(Menu::getPermission).collect(Collectors.toList());

            }
        }
        return null;
    }


    public MenuVO doToVo(Menu menu) {
        MenuVO menuVo = new MenuVO();
        BeanUtils.copyProperties(menu, menuVo);
        menuVo.setId(menu.getId());
        //菜单层数
        menuVo.setLevel(menu.getCode().split(",").length);
        return menuVo;
    }

    public List<MenuVO> doToVos(List<Menu> menuList) {
        if (menuList == null || menuList.isEmpty()) {
            return null;
        }
        List<MenuVO> result = new ArrayList<>();
        for (Menu menu : menuList) {
            result.add(doToVo(menu));
        }
        return result;
    }


}
